#include "TerrainDecal.h"

using namespace Ogre;

TerrainDecal::TerrainDecal(const String &name, const String &material, const Vector2 &dimensions, const Vector2 &position, SceneManager* sceneMgr, Real heightOffset, unsigned int resolution)
	: res(resolution), dim(dimensions), heightOffset(heightOffset)
{
	decal = new Ogre::ManualObject(name);
	
	decal->setCastShadows(false);
	decal->setDynamic(true);
	decal->setRenderQueueGroup(RENDER_QUEUE_WORLD_GEOMETRY_2);

	decal->begin(material);
		for(unsigned int i = 0; i <= res; i++)
		{
			for(unsigned int j = 0; j <= res; j++)
			{
				decal->position(Ogre::Vector3(i, 0, j));
				decal->textureCoord(i / (Real)res, j / (Real)res);
			}
		}

		for(unsigned int i = 0; i < res; i++)
		{
			for(unsigned int j = 0; j < res; j++)
			{
				decal->quad(
					i * (res + 1) + j,
					i * (res + 1) + j + 1,
					(i + 1) * (res + 1) + j + 1,
					(i + 1) * (res + 1) + j);
			}
		}
	decal->end();
	m_sceneManager = sceneMgr;

	decalNode = sceneMgr->getRootSceneNode()->createChildSceneNode(name+"node");
	decalNode->attachObject(decal);

	query = m_sceneManager->createRayQuery(Ray());

	moveTo(position);
}

TerrainDecal::~TerrainDecal()
{
	delete query;
	decalNode->detachAllObjects();
	decalNode->getParent()->removeChild(decalNode);
	delete decal;
}

void TerrainDecal::Init(SceneManager* sceneManager, String terreno_cfg, String walk_map)
{
		m_sceneManager = sceneManager;

        m_sceneManager->setWorldGeometry(terreno_cfg);
		m_walkmap = new Image();
       // m_walkmap->load(walk_map, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
		m_walkmap->load(walk_map, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
        // Get terrain dimensions from terrain config file
        ConfigFile cf;
        DataStreamPtr dsp = Ogre::ResourceGroupManager::getSingleton().openResource(terreno_cfg);
        cf.load(dsp, "\t:=", true);
        tamX = atof( cf.getSetting( "PageWorldX" ).c_str() );
        tamZ = atof( cf.getSetting( "PageWorldZ" ).c_str() );
}


void TerrainDecal::moveTo(const Vector2 &position)
{
	Real xBegin = position.x - (dim.x / 2);
	Real zBegin = position.y - (dim.y / 2);

	Real xWidth = dim.x / res;
	Real zWidth = dim.y / res;

	decal->beginUpdate(0);
	for(unsigned int i = 0; i <= res; i++)
	{
		for(unsigned int j = 0; j <= res; j++)
		{
			Real x = xBegin + (xWidth * i);
			Real z = zBegin + (zWidth * j);
			Real y = getHeight(x, z) + heightOffset;
			decal->position(x, y, z);
			decal->textureCoord(i / (Real)res, j / (Real)res);
		}
	}

	for(unsigned int i = 0; i < res; i++)
	{
		for(unsigned int j = 0; j < res; j++)
		{
			decal->quad(
				i * (res + 1) + j,
				i * (res + 1) + j + 1,
				(i + 1) * (res + 1) + j + 1,
				(i + 1) * (res + 1) + j);
		}
	}
	decal->end();

}

void TerrainDecal::hide()
{
	decal->setVisible(false);
}

void TerrainDecal::show()
{
	decal->setVisible(true);
}

bool TerrainDecal::isVisible() const
{
	return decal->getVisible();
}

Real TerrainDecal::getHeight(Real x, Real z)
{
	query->setRay(Ray(Vector3(x, 5000, z), Vector3::NEGATIVE_UNIT_Y));

	RaySceneQueryResult &result = query->execute();
	RaySceneQueryResult::iterator i = result.begin();

	if(i != result.end() && i->worldFragment)
		return i->worldFragment->singleIntersection.y;

	return 0;
}

Real TerrainDecal::getHeightAt(Vector3 position)
{
        float x = position.x;
        float z = position.z;
        Real terrainHeight = 0.0;

        // The ray scene query pointer
        RaySceneQuery *mRaySceneQuery = m_sceneManager->createRayQuery(Ray());

        // Setup the scene query
        Ray elementRay(Vector3(x, 5000.0f, z), Vector3::NEGATIVE_UNIT_Y);
        mRaySceneQuery->setRay(elementRay);

        // Perform the scene query
        RaySceneQueryResult &result = mRaySceneQuery->execute();
        RaySceneQueryResult::iterator itr = result.begin();

        // Get the results
        if (itr != result.end() && itr->worldFragment)
                terrainHeight = itr->worldFragment->singleIntersection.y;

        // We created the query, and we are also responsible for deleting it.
        m_sceneManager->destroyQuery(mRaySceneQuery);

        return terrainHeight;
}
bool TerrainDecal::isWalkable(float x, float z)
{
        float tx = x/tamX;
        float tz = z/tamZ;
        int pix_x = (int)(tx*m_walkmap->getWidth());
        int pix_z = (int)(tz*m_walkmap->getHeight());

        // Walkable colour is hardcoded to WHITE
        return m_walkmap->getColourAt(pix_x,pix_z,0) == ColourValue(1.0, 1.0, 1.0, 1.0);
}